﻿#include <vtkLineSource.h>
#include <vtkPolyData.h>
#include <vtkSmartPointer.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkAxesActor.h>
#include <vtkConeSource.h>
#include <vtkTransform.h>
#include <vtkCamera.h>

#include <QtDebug>
#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);

/** 程序演示了如何旋转actor, 两种方法，1是通过vtkTransform, 2是通过直接调用Rotate达到同样的效果，注意orientaion.
  */



#define LINE_LEN 2.

vtkSmartPointer<vtkActor> createConeActor();
void createLineActors(vtkSmartPointer<vtkActor> actor1[3]);
vtkSmartPointer<vtkAxesActor> createAxesActor();
vtkSmartPointer<vtkActor> createLineActor();

/// 创建数据角色
vtkSmartPointer<vtkActor> createConeActor()
{
    vtkSmartPointer<vtkConeSource> sphereSource =
        vtkSmartPointer<vtkConeSource>::New();
    sphereSource->SetRadius(.5);
    sphereSource->SetCenter(0, 0, 0);
    vtkSmartPointer<vtkPolyDataMapper> mapper =
        vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputConnection(sphereSource->GetOutputPort());
    vtkSmartPointer<vtkActor> actor =
        vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);

    return actor;
}

vtkSmartPointer<vtkActor> createLineActor()
{
    vtkSmartPointer<vtkLineSource> lineSource =
        vtkSmartPointer<vtkLineSource>::New();
    lineSource->SetPoint1(0, 0, 0);
    lineSource->SetPoint2(LINE_LEN, LINE_LEN, 0);
    lineSource->Update();

    vtkSmartPointer<vtkPolyDataMapper> mapper =
        vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputConnection(lineSource->GetOutputPort());
    vtkSmartPointer<vtkActor> actor =
        vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
    actor->GetProperty()->SetColor(1, 0, 0);
    actor->SetPosition(0, 0, 0);

    return actor;
}

void createLineActors(vtkSmartPointer<vtkActor> actor1[3])
{
    vtkSmartPointer<vtkLineSource> lineSourceX =
        vtkSmartPointer<vtkLineSource>::New();
    lineSourceX->SetPoint1(0, 0, 0);
    lineSourceX->SetPoint2(LINE_LEN, 0, 0);
    lineSourceX->Update();
    vtkSmartPointer<vtkLineSource> lineSourceY =
        vtkSmartPointer<vtkLineSource>::New();
    lineSourceY->SetPoint1(0, 0, 0);
    lineSourceY->SetPoint2(0, LINE_LEN, 0);
    lineSourceY->Update();
    vtkSmartPointer<vtkLineSource> lineSourceZ =
        vtkSmartPointer<vtkLineSource>::New();
    lineSourceZ->SetPoint1(0, 0, 0);
    lineSourceZ->SetPoint2(0, 0, LINE_LEN);
    lineSourceZ->Update();

    vtkSmartPointer<vtkPolyDataMapper> MapperX =
        vtkSmartPointer<vtkPolyDataMapper>::New();
    MapperX->SetInputConnection(lineSourceX->GetOutputPort());
    vtkSmartPointer<vtkPolyDataMapper> MapperY =
        vtkSmartPointer<vtkPolyDataMapper>::New();
    MapperY->SetInputConnection(lineSourceY->GetOutputPort());
    vtkSmartPointer<vtkPolyDataMapper> MapperZ =
        vtkSmartPointer<vtkPolyDataMapper>::New();
    MapperZ->SetInputConnection(lineSourceZ->GetOutputPort());

//    vtkSmartPointer<vtkActor> actor1[3];
    for (int i = 0; i < 3; i++)
    {
        actor1[i] = vtkSmartPointer<vtkActor>::New();
        actor1[i]->GetProperty()->SetOpacity(0.3);
    }
    actor1[0]->SetMapper(MapperX);
    actor1[1]->SetMapper(MapperY);
    actor1[2]->SetMapper(MapperZ);
    actor1[0]->GetProperty()->SetColor(1, 0, 0);
    actor1[1]->GetProperty()->SetColor(0, 1, 0);
    actor1[2]->GetProperty()->SetColor(0, 0, 1);
    actor1[0]->SetPosition(0, 0, 0);
    actor1[1]->SetPosition(0, 0, 0);
    actor1[2]->SetPosition(0, 0, 0);
}

vtkSmartPointer<vtkAxesActor> createAxesActor()
{
    vtkSmartPointer<vtkAxesActor> actor2 =
        vtkSmartPointer<vtkAxesActor>::New();
    actor2->SetPosition(0, 0, 0);
    actor2->SetTotalLength(LINE_LEN, LINE_LEN, LINE_LEN);
    actor2->SetShaftType(0);
    actor2->SetAxisLabels(true);
    actor2->SetCylinderRadius(0.02);

    return actor2;
}

int main(int, char *[])
{
    // actorLines1/2
    vtkSmartPointer<vtkActor> actorLines1[4];
    createLineActors(actorLines1);
    actorLines1[3] =createLineActor();

    vtkSmartPointer<vtkActor> actorLines2[4];
    createLineActors(actorLines2);
    actorLines2[3] =createLineActor();

    // axesActor 1/ 2
    vtkSmartPointer<vtkAxesActor> actorAxes = createAxesActor();


    // 对render1 进行 transform
    vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
    transform->RotateZ(45);
    transform->RotateY(90);
    transform->RotateX(10);

    transform->Update();

    vtkMatrix4x4 *m = transform->GetMatrix();
    std::cout << "matrix:" << *m << std::endl;

    for (int i = 0; i < 4; i++)
    {
        actorLines1[i]->SetUserTransform(transform);
    }

    // 对render2 进行 rotate
    // test rotate
    for (int i = 0; i < 4; i++)
    {
        actorLines2[i]->RotateZ(45);
        actorLines2[i]->RotateY(90);
    }

    // rotate Z -> X -> Y
    double *angles = actorLines2[0]->GetOrientation();
    qDebug() << QString::asprintf("angles: %lf, %lf, %lf", angles[0], angles[1], angles[2]);


    vtkSmartPointer<vtkRenderer> renderer1 =
        vtkSmartPointer<vtkRenderer>::New();
    vtkSmartPointer<vtkRenderer> renderer2 =
        vtkSmartPointer<vtkRenderer>::New();

    vtkSmartPointer<vtkRenderWindow> renderWindow =
        vtkSmartPointer<vtkRenderWindow>::New();
    renderWindow->SetSize(800, 400);
    renderWindow->AddRenderer(renderer1);
    renderWindow->AddRenderer(renderer2);
    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
        vtkSmartPointer<vtkRenderWindowInteractor>::New();
    renderWindowInteractor->SetRenderWindow(renderWindow);

    double leftViewport[] = { 0.0, 0.0, 0.5, 1.0 };
    double rightViewport[] = { 0.5, 0.0, 1.0, 1.0 };


    for (int i = 0; i < 3; i++)
    {
        renderer1->AddActor(actorLines1[i]);
        renderer2->AddActor(actorLines2[i]);
    }
    renderer1->AddActor(actorAxes);
    renderer2->AddActor(actorAxes);


    renderer1->SetBackground(.3, .3, .5);
    renderer2->SetBackground(.2, .4, .5);

    renderer1->SetViewport(leftViewport);
    renderer2->SetViewport(rightViewport);

    renderer1->GetActiveCamera()->Azimuth(30);
    renderer1->GetActiveCamera()->Elevation(10);
    renderer2->GetActiveCamera()->Azimuth(30);
    renderer2->GetActiveCamera()->Elevation(10);

    renderWindow->Render();
    renderWindowInteractor->Start();

    return EXIT_SUCCESS;
}
